// ***** BEGIN LICENSE BLOCK *****
// Version: MPL 1.1/GPL 2.0/LGPL 2.1
//
// The contents of this file are subject to the Mozilla Public License Version
// 1.1 (the "License"); you may not use this file except in compliance with
// the License. You may obtain a copy of the License at
// http://www.mozilla.org/MPL/
//
// Software distributed under the License is distributed on an "AS IS" basis,
// WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
// for the specific language governing rights and limitations under the
// License.
//
// The Initial Developer of the Original Code is
//   Axel Nennker http://axel.nennker.de/ .
// Created by the Initial Developer are Copyright (C) 2011
// the Initial Developer. All Rights Reserved.

const Cc = Components.classes;
const Ci = Components.interfaces;
const Cu = Components.utils;
const Cr = Components.results;

Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");

function log(aMessage) {
//  Services.console.logStringMessage("DOMopenid: " + aMessage);
}

function DOMOpenidAPI(){

}

DOMOpenidAPI.prototype = {
  classDescription: "DOM OpenID",
  classID:          Components.ID("{d95a5350-5258-11e0-b8af-0800200c9a66}"),
  contractID:       "@openinfocard.com/domopenid;1",
  QueryInterface: XPCOMUtils.generateQI([Ci.nsIDOMGlobalPropertyInitializer,
                                         Ci.nsIObserver]),
  flags: Components.interfaces.nsIClassInfo.DOM_OBJECT,
  implementationLanguage: Components.interfaces.nsIProgrammingLanguage.JAVASCRIPT,
  
  observe: function DA_observe(aSubject, aTopic, aData)
  {
    if (aTopic == "inner-window-destroyed") {
      let windowID = aSubject.QueryInterface(Ci.nsISupportsPRUint64).data;
      let innerWindowID = this.window.QueryInterface(Ci.nsIInterfaceRequestor).
                            getInterface(Ci.nsIDOMWindowUtils).currentInnerWindowID;
      if (windowID == innerWindowID) {
        delete this.window;
        delete this.sandbox;
        Services.obs.removeObserver(this, "inner-window-destroyed");
      }
    }
  },
  
  init: function DC_init(aWindow)
  {
    let self = this;
    this.window = XPCNativeWrapper.unwrap(aWindow);
    this.sandbox = Cu.Sandbox(this.window,
        { sandboxPrototype: this.window, wantXrays: false });
    try {
      this.xulWindow = aWindow.QueryInterface(Ci.nsIDOMWindow)
      .QueryInterface(Ci.nsIInterfaceRequestor)
      .getInterface(Ci.nsIWebNavigation)
      .QueryInterface(Ci.nsIDocShellTreeItem)
      .rootTreeItem
      .QueryInterface(Ci.nsIInterfaceRequestor)
      .getInterface(Ci.nsIDOMWindow)
      .QueryInterface(Ci.nsIDOMChromeWindow);
    } catch (e) {
      Cu.reportError(e);
    }

    Services.obs.addObserver(this, "inner-window-destroyed", false);
    
    let obj = {
      getPreferredOpenidProvider: self.getPreferredOpenidProvider.bind(self),
      __exposedProps__ : {
    	getPreferredOpenidProvider:"r"
      }
    };
    
    return obj;
  },

  getHelperForLanguage : function DAPI_getHelperForLanguage(count) {return null;},
  getInterfaces : function DAPI_getInterfaces(count) {
    var interfaceList = [nsIDOMGlobalPropertyInitializer];
    count.value = interfaceList.length;
    return interfaceList;
  },


  getPreferredOpenidProvider: function DAPI_getPreferredOpenidProvider(aCallback) {
    log("getPreferredOpenidProvider window.document=" + this.window.document);
    if (!(typeof aCallback == "function")) {
      let exception =
        new Components.Exception("First argument should be a function",
                                 Cr.NS_ERROR_INVALID_ARG,
                                 Components.stack.caller);
      throw exception;
    }
    log("getPreferredOpenidProvider callback=" + aCallback);
    return this.prompt(aCallback);
  },
  
  prompt: function(callback) {
    var pm = Cc["@mozilla.org/permissionmanager;1"].getService(Ci.nsIPermissionManager);

    var iOService = Components.classes["@mozilla.org/network/io-service;1"]
      .getService(Components.interfaces.nsIIOService);
    var requestingURI = iOService.newURI(this.window.document.location,null,null);
    var result = pm.testExactPermission(requestingURI, "preferredopenid");

    if (result == Ci.nsIPermissionManager.ALLOW_ACTION) {
      var OpenIdStorage = Components.classes['@openinfocard.com/openidstorage;1']
      .getService().wrappedJSObject;
      var preferredOpenidProvider = OpenIdStorage.getPreferredOpenID();
      return preferredOpenidProvider;
    }

    if (result == Ci.nsIPermissionManager.DENY_ACTION) {
      return;
    }

    function setPagePermission(uri, allow) {
      if (allow == true)
        pm.add(uri, "preferredopenid", Ci.nsIPermissionManager.ALLOW_ACTION);
      else
        pm.add(uri, "preferredopenid", Ci.nsIPermissionManager.DENY_ACTION);
    }

//    function getChromeWindow(aWindow) {
//      var chromeWin = aWindow
//        .QueryInterface(Ci.nsIInterfaceRequestor)
//        .getInterface(Ci.nsIWebNavigation)
//        .QueryInterface(Ci.nsIDocShellTreeItem)
//        .rootTreeItem
//        .QueryInterface(Ci.nsIInterfaceRequestor)
//        .getInterface(Ci.nsIDOMWindow)
//        .QueryInterface(Ci.nsIDOMChromeWindow);
//      return chromeWin;
//    }

    var requestingWindow = this.window.top;
    var chromeWindowObject = this.xulWindow.wrappedJSObject;
    var tabbrowser = chromeWindowObject.gBrowser;
    var browser = tabbrowser.getBrowserForDocument(requestingWindow.document);
    var notificationBox = tabbrowser.getNotificationBox(browser);

    var notification = notificationBox.getNotificationWithValue("openid");
    if (!notification) {
      var bundleService = Cc["@mozilla.org/intl/stringbundle;1"].getService(Ci.nsIStringBundleService);
      var browserBundle = bundleService.createBundle("chrome://openidnascar/locale/openid.properties");

      var self = this;
      
      var buttons = [{
              label: browserBundle.GetStringFromName("openid.sharepreferredprovider"),
              accessKey: browserBundle.GetStringFromName("openid.sharepreferredprovider.accesskey"),
              callback: function(notification) {
                  var elements = notification.getElementsByClassName("rememberChoice");
                  if (elements.length && elements[0].checked)
                      setPagePermission(requestingURI, true);
                  var OpenIdStorage = Components.classes['@openinfocard.com/openidstorage;1']
                    .getService().wrappedJSObject;
                  var preferredOpenidProvider = OpenIdStorage.getPreferredOpenID();
                  if (preferredOpenidProvider) {
                    preferredOpenidProvider = unescape(preferredOpenidProvider);
                  }
                  try {
                    var sbCallback = function() {callback(preferredOpenidProvider);};
                    self.sandbox.importFunction(sbCallback, "sbCallback");
                    Cu.evalInSandbox("sbCallback();",
                                     self.sandbox, "1.8", "DOMOpenID", 178);
                  } catch(e) {
                    Cu.reportError(e);
                  }
              },
          },
          {
              label: browserBundle.GetStringFromName("openid.dontsharepreferredprovider"),
              accessKey: browserBundle.GetStringFromName("openid.dontsharepreferredprovider.accesskey"),
              callback: function(notification) {
                  var elements = notification.getElementsByClassName("rememberChoice");
                  if (elements.length && elements[0].checked)
                      setPagePermission(requestingURI, false);
                  try {
                    callback();
                  } catch(e) {
                    Cu.reportError(e);
                  }
              },
          }];

      log("requestingURI.spec=" + requestingURI.spec);
      var host;
      try {
        host = requestingURI.host;
        log("requestingURI.host=" + requestingURI.host);
      } catch(e) {}
      
      if (!host) {
        host = requestingURI.spec;
      }
      var message = browserBundle.formatStringFromName("openid.sitewantstoknow",
                                                       [host], 1);

      var newBar = notificationBox.appendNotification(message,
                                                      "openid",
                                                      "chrome://openidnascar/content/openid-16x16.gif",
                                                      notificationBox.PRIORITY_INFO_HIGH,
                                                      buttons);

      // For whatever reason, if we do this immediately
      // (eg, without the setTimeout), the "link"
      // element does not show up in the notification
      // bar.
      function hacks_to_notification () {

        // Never show a remember checkbox inside the private browsing mode
        var inPrivateBrowsing = Cc["@mozilla.org/privatebrowsing;1"].
                                getService(Ci.nsIPrivateBrowsingService).
                                privateBrowsingEnabled;
        if (!inPrivateBrowsing) {
          var checkbox = newBar.ownerDocument.createElementNS(
              "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul", 
              "checkbox");
          checkbox.className = "rememberChoice";
          checkbox.setAttribute("label", browserBundle.GetStringFromName("openid.remember"));
          newBar.appendChild(checkbox);
        }
      };

      chromeWindowObject.setTimeout(hacks_to_notification, 0);

    }
  },
};

var NSGetFactory = XPCOMUtils.generateNSGetFactory([DOMOpenidAPI]);
